package vehimania
{
	import flash.events.Event;
	import flash.geom.Point;

	import mapkit.MapEvent;
	import mapkit.MapLayer;
	import mapkit.carto.Location;
	import mapkit.layers.MapGraphic;

	[Style(name="vehicleSkin", type="Class", inhreit="no")]
	[Style(name="selectSkin", type="Class", inhreit="no")]
	public class VehicleLayer extends MapLayer
	{
		private var _step:Number=6;

		public function get step():Number
		{
			return _step;
		}

		public function set step(value:Number):void
		{
			_step=value;
		}

		private var _vehicle:MapGraphic=new MapGraphic();

		public function get vehicle():MapGraphic
		{
			return _vehicle;
		}

		private var _select:MapGraphic=new MapGraphic();

		public function get select():MapGraphic
		{
			return _select;
		}

		private var _firstPlace:Location=new Location(0, 0);

		public function get firstPlace():Location
		{
			return _firstPlace;
		}

		public function set firstPlace(value:Location):void
		{
			_firstPlace=value;
		}

		override public function get handlerTypes():Array
		{
			return [VehicleControl];
		}

		override protected function load():void
		{
			super.load();
			var ctrl:VehicleControl=map.getHandler(VehicleControl) as VehicleControl;
			ctrl.addEventListener(VehicleControlEvent.AHEAD, aheadHandler);
			ctrl.addEventListener(VehicleControlEvent.BACK, backHandler);
			ctrl.addEventListener(VehicleControlEvent.LEFT, leftHandler);
			ctrl.addEventListener(VehicleControlEvent.RIGHT, rightHandler);
			ctrl.addEventListener(VehicleControlEvent.STOP, stopHandler);
			ctrl.addEventListener(VehicleControlEvent.SELECT, selectHandler);
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);

			_vehicle.map=map;
			_vehicle.locator=map.locator;
			_select.map=map;
			_select.locator=map.locator;
			_vehicle.feature.shape=new Location(_firstPlace.x, _firstPlace.y, _firstPlace.srid);
			_select.feature.shape=new Location(_firstPlace.x, _firstPlace.y, _firstPlace.srid);
			_select.visible=false;
			addChild(_vehicle);
			addChild(_select);
			invalidateDisplayList();
		}

		override protected function unload():void
		{
			var ctrl:VehicleControl=map.getHandler(VehicleControl) as VehicleControl;
			if (ctrl)
			{
				ctrl.removeEventListener(VehicleControlEvent.AHEAD, aheadHandler);
				ctrl.removeEventListener(VehicleControlEvent.BACK, backHandler);
				ctrl.removeEventListener(VehicleControlEvent.LEFT, leftHandler);
				ctrl.removeEventListener(VehicleControlEvent.RIGHT, rightHandler);
				ctrl.removeEventListener(VehicleControlEvent.STOP, stopHandler);
				ctrl.removeEventListener(VehicleControlEvent.SELECT, selectHandler);

				removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}
			super.unload();
		}

		override protected function updateMap(event:MapEvent=null):void
		{
			super.updateMap(event);

			invalidateDisplayList();
		}

		override public function styleChanged(styleProp:String):void
		{
			super.styleChanged(styleProp);

			var allStyles:Boolean=(styleProp == null || styleProp == "styleName");
			if (allStyles || styleProp == "vehicleSkin" || styleProp == "selectSkin")
			{
				var vicon:*=getStyle("vehicleSkin");
				_vehicle.setStyle("skin", vicon);
				var sicon:*=getStyle("selectSkin");
				_select.setStyle("skin", sicon);
				invalidateDisplayList();
			}
		}

		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);

			_vehicle.invalidateDisplayList();
			_select.invalidateDisplayList();
		}

		protected var aheadCounter:int=0;
		protected var backCounter:int=0;
		protected var leftCounter:int=0;
		protected var rightCounter:int=0;

		protected function aheadHandler(event:VehicleControlEvent):void
		{
			aheadCounter++;
		}

		protected function backHandler(event:VehicleControlEvent):void
		{
			backCounter++;
		}

		protected function leftHandler(event:VehicleControlEvent):void
		{
			leftCounter++;
		}

		protected function rightHandler(event:VehicleControlEvent):void
		{
			rightCounter++;
		}

		protected function stopHandler(event:VehicleControlEvent):void
		{
			_vehicle.invalidateWhere();
		}

		protected function selectHandler(event:VehicleControlEvent):void
		{
			_select.anchor=_vehicle.anchor;
			_select.invalidateWhere();
			_select.visible=true;
		}

		protected const NUM_ROTATION:int=32;

		protected var direction:int=0;

		protected function touchSideFilter():void
		{
			var pos:Point=_vehicle.anchor;
			if (pos.x < 0)
			{
				pos.x+=map.width;
			}
			if (pos.x > map.width)
			{
				pos.x-=map.width;
			}
			if (pos.y < 0)
			{
				pos.y+=map.height;
			}
			if (pos.y > map.height)
			{
				pos.y-=map.height;
			}
			_vehicle.anchor=pos;
		}

		protected function moveFilter():void
		{
			var pos:Point=_vehicle.anchor;
			var move:Number=(aheadCounter - backCounter) * _step;
			if (aheadCounter > 0 || backCounter > 0)
			{
				pos.x+=move * Math.cos(2 * Math.PI * direction / NUM_ROTATION);
				pos.y+=move * Math.sin(2 * Math.PI * direction / NUM_ROTATION);
			}
			_vehicle.anchor=pos;
			aheadCounter=0;
			backCounter=0;
		}

		protected function rotateFilter():void
		{
			if (leftCounter > 0 || rightCounter > 0)
			{
				direction=((direction + rightCounter - leftCounter) % NUM_ROTATION +
					NUM_ROTATION) % NUM_ROTATION;
				_vehicle.rotation=direction * 360 / NUM_ROTATION;
				leftCounter=0;
				rightCounter=0;
			}
		}

		protected function enterFrameHandler(event:Event):void
		{
			moveFilter();
			rotateFilter();
			touchSideFilter();
		}
	}
}